from KThread import KThread as kthread
from os import linesep
from time import sleep
import gtk
import pango
import gtk.glade
import gobject

def _(txt):
    return txt
    
def setcm_(reference):
    global _
    _ = reference

class ConnectionManager(object):
    def __init__(self,wTree,parent,connection):
        self.delayedcursorchangedflag = None
        self.c = connection
        self.parent = parent
        self.me = wTree
        self.treeviews = ["treeview0","treeview1","treeview2","treeview3","treeview4"]
        for i in self.treeviews:
            widget = self.me.get_widget(i)
            widget.connect("button-press-event",self.__buttonpress)

        self.tryexit = False
        self.killable = True
        self.rthread = None
        self.showable = True
        self.__initialize_treeview()
        self.itn()
        
    def get_protocol(self):
        return self.c.protocol
        
    def itn(self):
        columntitles = [_("torrentname"),_("torrentsize"),"%",_("torrentspeed"),_("torrentinfo")]
        for i in range(len(self.treeviews)):
            k = self.me.get_widget(self.treeviews[i])
            if i == 1:
                aux = columntitles[0:3]+columntitles[4:]
                for j in range(len(aux)):
                    k.get_column(j).set_title(aux[j])
                    
            else:
                aux = columntitles
                for j in range(len(aux)):
                    k.get_column(j).set_title(aux[j])
                    
                    
        
    def __initialize_treeview(self):
        titles = ("hash","status","torrentname","torrentsize",None,"%",None,"torrentspeed",None,None,None,"torrentinfo")
        for pk in range(len(self.treeviews)):
            k = self.treeviews[pk]
            widget = self.me.get_widget(k)
            model = widget.get_model()
            if model != None:
                model.clear()
                widget.set_model(None)
                for i in widget.get_columns():
                    widget.remove_column(i)

            model = gtk.ListStore(  gobject.TYPE_STRING,
                                    gobject.TYPE_INT,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_STRING,
                                    gobject.TYPE_STRING,
                                    gtk.gdk.Pixbuf,
                                    gobject.TYPE_STRING,
                                    gtk.gdk.Pixbuf,
                                    gobject.TYPE_STRING,
                                    gtk.gdk.Pixbuf,
                                    gobject.TYPE_STRING)
            
            self.me.get_widget(k).set_model(model)
            self.me.get_widget(k).get_selection().set_mode(gtk.SELECTION_MULTIPLE)
            
            for i in (2,3,5,7,11):
                if i in (3,5):
                    # SIZE & PERCENT
                    column = gtk.TreeViewColumn(titles[i])
                    render = gtk.CellRendererText()
                    render.set_property("alignment", pango.ALIGN_RIGHT)
                    column.pack_start(render, expand=True)
                    column.add_attribute(render, 'text', i)
                    render = gtk.CellRendererText()
                    render.set_property("alignment", pango.ALIGN_LEFT)
                    column.pack_start(render, expand=False)
                    column.add_attribute(render, 'text', i+1)
                elif i == 7:
                    # DOWN & UP
                    column = gtk.TreeViewColumn(titles[i])
                    start = 0
                    if pk == 4:
                        start = 2
                    for j in range(start,4):
                        if pk != 1:
                            if j%2==0:
                                render = gtk.CellRendererPixbuf()
                                column.pack_start(render, expand=False)
                                column.add_attribute(render, 'pixbuf', i+j)
                            else:
                                render = gtk.CellRendererText()
                                column.pack_start(render, expand=False)
                                column.add_attribute(render, 'text', i+j)
                elif i == 11:
                    # INFO
                    column = gtk.TreeViewColumn(titles[i])
                    render = gtk.CellRendererPixbuf()
                    column.pack_start(render, expand=False)
                    column.add_attribute(render, 'pixbuf', i)

                    render = gtk.CellRendererText()
                    column.pack_start(render, expand=True)
                    column.add_attribute(render, 'text', i+1)
                else:
                    render = gtk.CellRendererText()
                    column = gtk.TreeViewColumn(titles[i], render,text=i)
                    if i == 2:
                        render.set_property("ellipsize", pango.ELLIPSIZE_END)
                        column.set_resizable(True)
                        column.set_expand(True)
                if not (pk == 1 and i==7):
                    self.me.get_widget(k).append_column(column)

    def enableadd(self,state=True):
        for i in ("menuadd","btnadd","btnadd1","toolbutton1","menuitem9"):
            self.me.get_widget(i).set_sensitive(state)

    def unselect_all(self):
        self.me.get_widget(self.treeviews[self.parent.currentpage]).get_selection().unselect_all()
        self.__cursorchanged()

    def __buttonpress(self,widget,event):
        deselect = False
        if event.button == 3:
            x = int(event.x)
            y = int(event.y)
            time = event.time
            pthinfo = widget.get_path_at_pos(x, y)
            if pthinfo == None:
                self.unselect_all()
            else:
                selected_yet = False
                items = widget.get_selection().get_selected_rows()[1]
                if pthinfo[0] in items:
                    selected_yet = True
                if not selected_yet:
                    path, col, cellx, celly = pthinfo
                    widget.grab_focus()
                    widget.set_cursor( path, col, 0)
                    self.__cursorchanged()
            self.me.get_widget("menu4").popup( None, None, None, event.button, time)
            return True
        elif widget.get_path_at_pos(int(event.x), int(event.y))==None:
            self.unselect_all()
            return True
        else:
            self.__delayedcursorchanged()
            return False
    
    def __delayedcursorchanged(self,a=None,b=None,c=None,e=None,ufo=False):
        if ufo:
            sleep(0.05)
            self.__delayedcursorchangedflag = None
            gtk.gdk.threads_enter()
            self.__cursorchanged()
            gtk.gdk.threads_leave()
            
        else:
            if self.delayedcursorchangedflag != None:
                self.__delayedcursorchangedflag.kill()
            
            self.__delayedcursorchangedflag = kthread(target=self.__delayedcursorchanged,kwargs={"ufo":True})
            self.__delayedcursorchangedflag.start()

    def __cursorchanged(self,*args):
        widget = self.me.get_widget(self.treeviews[self.parent.currentpage])
        items = widget.get_selection().get_selected_rows()[1]
        model = widget.get_model()
        start = False
        pause = False
        remove = False
        for i in items:
            state = model[i[0]][1]
            remove = True
            if state == 0:
                start = True
            elif state == 1:
                pause = True
            elif state == 2:
                pause = True
            elif state == 3:
                pause = True
        for i in ("menuplay","btnplay","btnplay1","toolbutton2","menuitem6"):
            self.me.get_widget(i).set_sensitive(start)
        for i in ("menupause","btnpause","btnpause1","toolbutton3","menuitem7"):
            self.me.get_widget(i).set_sensitive(pause)
        for i in ("menuremove","btnremove","btnremove1","toolbutton4","menuitem8"):
            self.me.get_widget(i).set_sensitive(remove)

    def clearmodel(self):
        #gtk.gdk.threads_enter()
        for i in self.treeviews:
            model = self.me.get_widget(i).get_model()
            for j in model:
                model.remove(j.iter)
        #gtk.gdk.threads_leave()

    def disconnect(self):
        if self.refresh_running():
            self.refresh_stop()
        self.enableadd(False)
        self.clearmodel()
        for i in ("label24","label25",):
            self.me.get_widget(i).set_label("0 B/s")
        self.c.session_logout()
        
    def stop_daemon(self):
        self.refresh_stop()
        self.parent.mainStatus(_("tdaemonkilling"))
        self.c.stop_daemon()
        counter = 0
        while counter < 5:
            info = self.c.daemon_running()
            if not info[0]:
                break
            print "Daemon is alive with pid %d" % (info[1])
            counter += 1
            sleep(0.5)
        if counter > 4:
            print "It's taking too much time, sending kill signal"
            self.c.exec_commands(["kill -9 %d" % info[1]])
            
    def start_daemon(self):
        self.c.start_daemon()
        for i in range(6):
            sleep(2)
            if self.c.daemon_running()[0]:
                if not self.refresh_running():
                    self.rowrefresh(exit=False)
                break

    def selected_hashes(self,state=()):
        widget = self.me.get_widget(self.treeviews[self.parent.currentpage])
        widget.queue_draw()
        (store,path) = widget.get_selection().get_selected_rows()
        selected_hashes = []
        for i in path:
            if len(state) == 0 or store[i[0]][1] in state:
                selected_hashes.append(store[i[0]][0])
        return selected_hashes

    def select_hashes(self,hash_list):
        treeview = self.me.get_widget(self.treeviews[self.parent.currentpage])
        selection = treeview.get_selection()
        selection.set_mode(gtk.SELECTION_MULTIPLE)
        if len(hash_list)==0:
            selection.unselect_all()
        else:
            for i in treeview.get_model():
                if i[0] in hash_list:
                    selection.select_path(i.path)
                else:
                    selection.unselect_path(i.path)
        self.__cursorchanged()

    def rowrefresh(self,retrieve_info=True,loop=True,ufo=False,exit=True):
        if ufo == True:
            while not self.tryexit:
                try:
                    self.killable = True
                    while self.c.session == None:
                        sleep(1)
                    self.killable = False
                    if len(self.parent.tqueue)>0:
                        if self.c.daemon_running()[0]:
                            self.c.send_torrents(self.parent.tqueue)
                            self.parent.tqueue = []
                    a = self.c.do()
                    
                    if not a[0]:
                        self.showable = False
                        
                        if a[1]==2:
                            print "Sync error"
                            self.parent.mainStatus(_("concurrencyerror"))
                        else:
                            self.parent.statedaemon(False)
                            break
                        
                        raise StopIteration()
                    else:
                        self.parent.get_prefs()
                        self.parent.statedaemon(True)
                        self.showable = True
                        
                        line_hash = a[1][-2].strip().split(linesep)
                        lines = a[1][-1].strip().split(linesep)

                        for i in (line_hash,lines):
                            for j in range(i.count("")):
                                i.remove("")

                        count = len(line_hash)
                        count2 = len(lines)
                        

                        tmparray = []
                        if count != count2:
                            self.parent.mainStatus(_("concurrencyerror"))
                        elif 0 in (count,count2,):
                            self.parent.mainStatus(_("nodataerror"))
                        else:
                            # CHECK IF LINES ARE ORDERED
                            line_list = []
                            for i in line_hash:
                                tosearch = i[len(i.split()[0]):].strip()
                                for j in lines:
                                    if j.strip()[:len(tosearch)]==tosearch:
                                        line_list.append(j)
                                        break
                                        
                            for i in range(count):
                                hash = line_hash[i].split()[0].strip()
                                filename = line_hash[i][len(hash):].strip()
                                internal_info = [ hash , -1 ]
                                info = [ None, filename , None , None , None , None , None , None, None , None , None, None ]
                                linea = line_list[i].replace(filename , "").strip()

                                status = gtk.Image()
                                status.set_from_stock(gtk.STOCK_GO_UP,gtk.ICON_SIZE_BUTTON)

                                if "downloading at" in linea:
                                    internal_info[1] = 1
                                    # (701 MiB) - 0.00% downloading at 0.00 B/s (UL at 0.00 B/s), stalled
                                    # NAME (SIZE MiB) - PERCENT% downloading at DSPEED KiB/s (UL at USPEED B/s), done in 11 hours 3 minutes
                                    size = linea.split("(")[1].split(")")[0].strip()
                                    info[2] = size.split()[0].strip()
                                    info[3] = size.split()[1].strip()
                                    info[4] = linea.split("-")[1].split("%")[0].strip()
                                    info[5] = "%"
                                    info[6] = self.parent.icon_down
                                    info[7] = linea.split("downloading at")[1].split("(")[0].strip()
                                    info[8] = self.parent.icon_up
                                    info[9] = linea.split("(UL at")[1].split(")")[0].strip()

                                    if "done in" in linea:
                                        info[10] = self.parent.icon_info
                                        tiempo = linea.split("done in")[1].strip()

                                        for i in ("months","month","weeks","week",
                                                  "days","day","hours","hour",
                                                  "minutes","minute","seconds","second"):
                                            tiempo = tiempo.replace(i,_(i))

                                        info[11] = _("estimateddtime")
                                        if info[11][-1]==":":
                                            info[11] += " "
                                        info[11] += tiempo
                                    elif "stalled" in linea:
                                        info[10] = self.parent.icon_help
                                        info[11] = _("unknownestimate")
                                        rest = linea.split("stalled")[1]
                                        if "[" in rest and "]" in rest.split("[")[1]:
                                            info[11] += " (" + rest.split("[")[1].split("]")[0] + ") "
                                    else:
                                        info[11] = linea.split(")")[2].strip()
                                elif "seeding at" in linea:
                                    internal_info[1] = 2
                                    # NAME (SIZE MiB) - 100% seeding at USPEED B/s [0.00]
                                    size = linea.split("(")[1].split(")")[0].strip()
                                    info[2] = size.split()[0].strip()
                                    info[3] = size.split()[1].strip()
                                    info[4] = "100"
                                    info[8] = self.parent.icon_up
                                    info[9] = linea.split("seeding at")[1].split("[")[0].strip()
                                    info[10] = self.parent.icon_info
                                    info[11] = _("seeding")
                                elif "stopped" in linea:
                                    internal_info[1] = 0
                                    size = linea.split("(")[1].split(")")[0].strip()
                                    info[2] = size.split()[0].strip()
                                    info[3] = size.split()[1].strip()
                                    info[4] = linea.split("-")[1].split("%")[0].strip()
                                    info[10] = self.parent.icon_pause
                                    info[11] = _("paused")
                                elif "checking files" in linea:
                                    internal_info[1] = 3
                                    # (701 MiB) - 20.1% checking files
                                    size = linea.split("(")[1].split(")")[0].strip()
                                    info[2] = size.split()[0].strip()
                                    info[3] = size.split()[1].strip()
                                    info[4] = linea.split("-")[1].split("%")[0].strip()
                                    info[10] = self.parent.icon_find
                                    info[11] = _("checkingfiles")
                                elif "error" in linea.lower():
                                    info[10] = self.parent.icon_error
                                    info[11] = linea
                                else:
                                    if linea.count("(") > 0 and linea.count(")")>0:
                                        size = linea.split("(")[1].split(")")[0].strip()
                                        info[2] = size.split()[0].strip()
                                        info[3] = size.split()[1].strip()

                                    if linea.count("-")> 0 and linea.count("%") > 0:
                                        info[4] = linea.split("-")[1].split("%")[0].strip()

                                    info[10] = self.parent.icon_help
                                    info[11] = _("unknownstate")

                                if info[4]!=None:
                                    info[5] = "%"
                                
                                tmparray.append(internal_info+info[1:])
                            
                            current = []
                            downs = 0
                            uplos = 0
                            for i in tmparray:
                                if i[8]:
                                    value = float(i[8].split()[0])
                                    if "KiB/s" in i[8]:
                                        value = value * 1024
                                    if "MiB/s" in i[8]:
                                        value = value * 1024 * 1024
                                    downs += value
                                        
                                if i[10]:
                                    value = float(i[10].split()[0])
                                    if "KiB/s" in i[10]:
                                        value = value * 1024
                                    if "MiB/s" in i[10]:
                                        value = value * 1024 * 1024
                                    uplos += value
                                    
                            downlabel = "B/s"
                            uplolabel = "B/s"
                            for i in ("KiB/s","MiB/s",):
                                if downs / 1024. > 1:
                                    downs = downs / 1024.
                                    downlabel = i
                                if uplos / 1024. > 1:
                                    uplos = uplos / 1024.
                                    uplolabel = i
                            
                            downaux = str(round(downs,2)) + " " + downlabel
                            uploaux = str(round(uplos,2)) + " " + uplolabel
                            
                            paused      = []
                            downloading = []
                            uploading   = []
                            done        = []
                            
                            for i in tmparray:
                                if i[1] in (0,3,):
                                    paused.append(i)
                                if i[1] == 1 and float(i[8].split()[0])>0.:
                                    downloading.append(i)
                                if i[1] in (1,2,) and float(i[10].split()[0])>0.:
                                    uploading.append(i)
                                if i[1] != 3 and i[5] == str(100):
                                    done.append(i)
                                    
                            gtk.gdk.threads_enter()
                            self.me.get_widget("label24").set_label(downaux)
                            self.me.get_widget("label25").set_label(uploaux)
                            for k,z in (("treeview0",tmparray),("treeview1",paused),
                                        ("treeview2",downloading),("treeview3",uploading),
                                        ("treeview4",done)):
                                model = self.me.get_widget(k).get_model()  
                                i = 0                                  
                                while i < len(model):
                                    found = False
                                    for j in range(len(z)):
                                        if model[i][0]==z[j][0]:
                                                model[i] = z.pop(j)
                                                found = True
                                                break
                                    if not found:
                                        model.remove(model[i].iter)
                                    else:
                                        i += 1
                                for i in z:  
                                    model.append(i)
                            gtk.gdk.threads_leave()
                except StopIteration:
                    pass
                #except Exception,y:
                #    print "ERROR: ",str(Exception),str(y)
                self.killable = True
                if loop:
                    timeout = self.get_timeout()
                    if self.showable:
                        show = self.parent.options.getboolean("DEFAULT","showtimeout")
                        if not show:
                            self.parent.mainStatus("")
                    else:
                        show = False

                    status_delay = 500
                    self.refresh_time = 0
                    while self.refresh_time < timeout and not self.tryexit:
                        resto = timeout - self.refresh_time
                        if  resto > status_delay:
                            sleep(status_delay/1000.)
                            self.refresh_time += status_delay
                        else:
                            sleep(resto/1000.)
                            self.refresh_time += resto

                        if show:
                            tmp = timeout-self.refresh_time
                            if tmp > 0:
                                info = "%d.%d\"" % (tmp/1000,(tmp%1000)/100)
                            else:
                                info = "..."
                            self.parent.mainStatus("%s" % (info))

                    self.killable = False
                else:
                    break
            self.killable = True
            self.rthread = None
        else:
            self.tryexit = False
            if not self.refresh_running():
                self.rthread = kthread(target=self.rowrefresh, kwargs={"retrieve_info":retrieve_info,"loop":loop,"ufo":True,"exit":True})
                self.rthread.start()
            else:
                self.refresh_now()
                
    def get_timeout(self):
        return self.parent.options.getint("DEFAULT","timeout")

    def refresh_now(self):
        if self.refresh_running():
            self.refresh_time = self.parent.options.getint("DEFAULT","timeout") + 1
        else:
            self.rowrefresh()

    def refresh_stop(self):
        if self.refresh_running():
            self.tryexit = True
            a = 50
            b = 0
            while not self.killable and b<a:
                b += 1
                sleep(0.1)
            if b==a:
                print "Refreshing loop out of control. Trying to kill."
            try:
                self.rthread.kill()
                print "Loop killed."
                self.rthread = None
            except:
                pass        

    def refresh_running(self):
        if self.rthread != None:
            return True
        return False


